package sockets;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;

import DB.AddFile;
import DB.ArrayOfChanges;
import DB.RenameFile;
import DB.SearchFile;
import Data.Declarations;

public class FileServer implements Runnable
{
	/**
	 * this class start to run the server. this class starts 3 threads that each one of them 
	 * listen to different port and wait for a connection.
	 * @author Erez
	 *
	 */

	
	public FileServer() {
	// TODO Auto-generated constructor stub
		
    }
	public void run()
	{
		System.out.println("FileServer started - general run");
		Thread t1=new Thread(new FileReciever());
		Thread t2=new Thread(new FileRenamer());
		Thread t3=new Thread(new FileDeleter());
		t1.start();
		t2.start();
		t3.start();
		System.out.println("FileServer started - end of general run");
	}
    private class FileReciever implements Runnable
    {
    	public void run()
    	{
		    ServerSocket servsock;
			try 
			{
				servsock = new ServerSocket(13267);
			    while (true) 
			    {
			      System.out.println("Start FileReciever...");
			      Socket sock = servsock.accept();
			      System.out.println("Accepted connection : " + sock);
			   // sendfile
			      new Thread(new getFile(sock)).run();
			    }
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    private class getFile implements Runnable
    {
    	private Socket sock;
    	private SearchFile searchDB;
    	public getFile(Socket sock) {
	// TODO Auto-generated constructor stub
    		this.sock=sock;
    		searchDB = new SearchFile();
    	}
	@Override
		public void run() 
		{
			// TODO Auto-generated method stub
			try 
			{
				int bytesRead;
				int current = 0;
				System.out.println("Connecting...");
				
	
				
	  		    InputStream in = sock.getInputStream();
	
	  		    DataInputStream din = new DataInputStream(in);
	
	  		   //First read the file name
	
	  		    String filename=din.readUTF();
	  		    if(searchDB.searchInDB(filename)==false)//means the file isn't in system, so we can add it
	  		    {
		  		    //now read the length (as a simple long)
		  		    
		  		    long filesize = din.readLong();
		  		    System.out.println(filesize);
		  		    byte [] bytes = new byte [(int) filesize];
		  		    FileOutputStream fos = new FileOutputStream(Declarations.instance.getServerFiles()+filename);
		  		    BufferedOutputStream bos = new BufferedOutputStream(fos);
		  		    bytesRead = in.read(bytes,0,bytes.length);
		  		    current = bytesRead;
		  		    do {
		  		       bytesRead = in.read(bytes, current, (bytes.length-current));
		  		       if(bytesRead >= 0) 
		  		    	   current = current+bytesRead;
		  		    } while(bytesRead > 0);
		
		  		    bos.write(bytes, 0 , current);
		  		    bos.flush();
		  		    bos.close();
		  		    
		  		    new AddFile(filename,null,null,0);
		  		    System.out.println("Recieved");
		  		    
		  		    //add to the array of changes
		  		    ArrayOfChanges.instance.addChange("created " + filename);
	  		    }
	  		    sock.close();
			}
		    catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
		    	  e.printStackTrace();
		
		    }
		    catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    }
    
    private class FileRenamer implements Runnable
    {
    	public void run()
    	{
    	
		    ServerSocket servsock;
			try 
			{
				servsock = new ServerSocket(13268);
			    while (true) 
			    {
			      System.out.println("start FileRenamer...");
			      Socket sock = servsock.accept();
			      System.out.println("Accepted connection : " + sock);
			   // sendfile
			      new Thread(new renameFile(sock)).run();
			    }
			} 
			catch (IOException e) 
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    private class renameFile implements Runnable
    {
    	private Socket sock;
    	private SearchFile searchDB;
    	public renameFile(Socket sock) {
	// TODO Auto-generated constructor stub
    		this.sock=sock;
    		searchDB = new SearchFile();
    	}
	@Override
		public void run() 
		{
			// TODO Auto-generated method stub
			try 
			{
				System.out.println("Connecting...");

	  		    InputStream in = sock.getInputStream();
	
	  		    DataInputStream din = new DataInputStream(in);
	
	  		   //First read the oldfile name
	
	  		    String oldname=din.readUTF();
	  		    String newname=din.readUTF();
	  		    
  		    	//means the file is in system and the new file is not, so we can add it
	  		    if(searchDB.searchInDB(oldname)==true && searchDB.searchInDB(newname)==false)
	  		    	
	  		    {
		  		    //now read the length (as a simple long)

		  		    new DB.RenameFile().renameInDB(oldname,newname);
		  		    System.out.println("Renamed");
		  		    
		  		    //add to the array of changes
		  		    ArrayOfChanges.instance.addChange("rename " + oldname + " " + newname);
	  		    }
	  		    sock.close();
			}
		    catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
		    	  e.printStackTrace();
		
		    }
		    catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    }
    private class FileDeleter implements Runnable
    {
    	public void run()
    	{
    	
		    ServerSocket servsock;
			try 
			{
				servsock = new ServerSocket(13269);
			    while (true) 
			    {
			      System.out.println("start FileDeleter...");
			      Socket sock = servsock.accept();
			      System.out.println("Accepted connection : " + sock);
			   // sendfile
			      new Thread(new deleteFile(sock)).run();
			    }
			} 
			catch (IOException e) 
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    private class deleteFile implements Runnable
    {
    	private Socket sock;
    	private SearchFile searchDB;
    	public deleteFile(Socket sock) {
	// TODO Auto-generated constructor stub
    		this.sock=sock;
    		searchDB = new SearchFile();
    	}
	@Override
		public void run() 
		{
			// TODO Auto-generated method stub
			try 
			{
				System.out.println("Connecting...");

	  		    InputStream in = sock.getInputStream();
	
	  		    DataInputStream din = new DataInputStream(in);
	
	  		   //First read the oldfile name
	
	  		    String filename=din.readUTF();
	  		    //means the file is in system and
	  		    if(searchDB.searchInDB(filename)==true) 
	  		    {	    	
		  		    //now read the length (as a simple long)
		  		    new DB.DeleteFile().deleteInDB(filename);
		  		    System.out.println("Deleted");
		  		    
		  		    //add to the array of changes
		  		    ArrayOfChanges.instance.addChange("deleted " + filename);
	  		    }
	  		    sock.close();
			}
		    catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
		    	  e.printStackTrace();
		
		    }
		    catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    }
	
}